﻿//+--------------------------------------------------------------------------------------------------------------------------------------------------------
//     
//Description: DefinitionViewModel. Main.
//Author: Aravind Ramarathinam (aravr@microsoft.com)
//Copyright © Microsoft Corporation
//Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 
//You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 
//
//THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, 
//INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. 
//See the Apache Version 2.0 License for specific language governing permissions and limitations under the License.
// 
//--------------------------------------------------------------------------------------------------------------------------------------------------------


using System;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Web.Script.Serialization;
using System.Windows.Forms;
using System.Windows.Input;
using VmroleAuthor.Commands;
using VmroleAuthor.Models;
using MessageBox = System.Windows.MessageBox;

namespace VmroleAuthor.ViewModels
{
    public class DefinitionViewModel : ViewModelBase, IRemoveChildItem
    {      
        readonly ObservableCollection<TreeViewItemViewModel> rootTreeViewItemViewModels;
        private int selectedTabIndex;

        public const string ToolHeader = "VM Role Authoring Tool";

        public DefinitionViewModel()
        {
            this.rootTreeViewItemViewModels = new ObservableCollection<TreeViewItemViewModel>();

            // Test:
            //VMRoleResourceExtensionDefinition resExtDef = MockTestObjects.GetVmRoleResourceExtension();         
            //VmRoleResourceExtensionViewModel resExtViewModel = new VmRoleResourceExtensionViewModel(resExtDef, null);
            //resExtViewModel.IsSelected = true;
            //resExtViewModel.IsExpanded = true;
            //this.rootTreeViewItemViewModels.Add(resExtViewModel);

            //ResourceDefinition resDef = MockTestObjects.GetVmRoleResourceDefinition();
            //VmRoleResourceDefinitionViewModel resourceDefinitionViewModel = new VmRoleResourceDefinitionViewModel(resDef, null, null, rootTreeViewItemViewModels);
            //resourceDefinitionViewModel.IsSelected = true;
            //resourceDefinitionViewModel.IsExpanded = true;
            //this.rootTreeViewItemViewModels.Add(resourceDefinitionViewModel);

            this.DefinitionTreeItemMenuCommandRouter = new DefinitionTreeItemMenuCommandRouter(this);
            this.SaveAllCommand = new RelayCommand(param => this.SaveAll(), param => this.CanSaveAll());

            this.ValidationResults = new ObservableCollection<CloudServiceModelValidationResult>();
            this.ValidateAllCommand = new RelayCommand(param => this.ValidateAll(), param => this.CanValidateAll());
        }

        public ObservableCollection<TreeViewItemViewModel> RootTreeViewItemViewModels
        {
            get { return this.rootTreeViewItemViewModels; }
        }


         public int SelectedTabIndex
        {
            get
            {
                return this.selectedTabIndex;
            }

            set
            {
                if (value == 1 && this.selectedTabIndex != value)
                {
                    foreach (TreeViewItemViewModel treeViewItemViewModel in this.rootTreeViewItemViewModels)
                    {
                        this.UpdatePrettyJson(treeViewItemViewModel);
                    }
                }
                this.selectedTabIndex = value;
                this.OnPropertyChanged("SelectedTabIndex");
            }
        }

        private void UpdatePrettyJson(TreeViewItemViewModel treeViewItemViewModel)
        {
           if (treeViewItemViewModel == null)
           {
               return;
           }
           IJsonOutput output = treeViewItemViewModel as IJsonOutput;
           if (output != null)
           {
               treeViewItemViewModel.OnPropertyChanged("PrettyJson");
               foreach (TreeViewItemViewModel child in treeViewItemViewModel.Children)
               {
                   UpdatePrettyJson(child);
               }
           }           
        }

        public DefinitionTreeItemMenuCommandRouter DefinitionTreeItemMenuCommandRouter { get; private set; }

        public void ValidateSelectedResourceExtensionTreeViewItem(VmRoleResourceExtensionViewModel resourceExtensionViewModel)
        {         
            this.ValidationResults.Clear();
            IProduceValidationResults produceValidationResults = resourceExtensionViewModel as IProduceValidationResults;
            Debug.Assert(produceValidationResults != null);
            produceValidationResults.UpdateValidationResults();
            foreach (CloudServiceModelValidationResult result in produceValidationResults.ValidationResults)
            {
                this.ValidationResults.Add(result);
            }          
        }  


        public ICommand SaveAllCommand
        {
            get;
            private set;
        }

        public bool CanSaveAll()
        {
            return true;
        }

        public void SaveAll()
        {
            foreach (ISaveToDisk viewModel in this.rootTreeViewItemViewModels)
            {                              
               viewModel.SaveToDisk();           
            }
        }
      
        /// <summary>
        /// Can throw exception
        /// InvalidCastException
        /// SerializationException exception
        /// </summary>
        /// <param name="resourceExtensionStorageInfo"></param>
        public void OpenAndAddNewResourceExtensionToTheView(ResourceExtensionStorageInfo resourceExtensionStorageInfo)
        {
            string resExtJsonDoc = System.IO.File.ReadAllText(resourceExtensionStorageInfo.JsonFileName);
            JavaScriptSerializer js = new JavaScriptSerializer();
            VMRoleResourceExtensionDefinition deserializedObject = js.Deserialize<VMRoleResourceExtensionDefinition>(resExtJsonDoc); 
            VmRoleResourceExtensionViewModel resExtViewModel = new VmRoleResourceExtensionViewModel(deserializedObject, resourceExtensionStorageInfo);
            resExtViewModel.IsSelected = true;
            resExtViewModel.IsExpanded = true;         
            this.rootTreeViewItemViewModels.Add(resExtViewModel);               
        }

        /// <summary>
        /// Can throw exception
        /// InvalidCastException
        /// SerializationException exception
        /// </summary>
        /// <param name="resourceExtensionStorageInfo"></param>
        /// <param name="isWindowsResourceExtension"></param>
        public void CreateAndAddNewResourceExtensionToTheView(ResourceExtensionStorageInfo resourceExtensionStorageInfo, bool isWindowsResourceExtension = true)
        {
            VmRoleResourceExtensionViewModel resExtViewModel = VmRoleResourceExtensionViewModel.CreateNewResourceExtension(resourceExtensionStorageInfo, isWindowsResourceExtension);
            resExtViewModel.IsSelected = true;
            resExtViewModel.IsExpanded = true;
            this.rootTreeViewItemViewModels.Add(resExtViewModel);         
        }

        /// <summary>
        /// Can throw exception
        /// InvalidCastException
        /// SerializationException exception
        /// </summary>      
        /// <param name="resourceDefinitionStorageInfo"></param>
        public void OpenAndAddNewResourceDefinitionToTheView(ResourceDefinitionStorageInfo resourceDefinitionStorageInfo)
        {
            string resDefJsonDoc = System.IO.File.ReadAllText(resourceDefinitionStorageInfo.JsonFileName);
            JavaScriptSerializer js = new JavaScriptSerializer();
            ResourceDefinition deserializedObject;

            try
            {
                deserializedObject = js.Deserialize<ResourceDefinition>(resDefJsonDoc);
            }           
            catch (Exception ex)
            {
                string jsMsg = ex.Message;
                string exMsg = ex.ToString();
                string dsMsg = string.Empty;
                string dxMsg = string.Empty;
                try
                {
                    //TO get more detailed exception
                    using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(resourceDefinitionStorageInfo.JsonFileName)))
                    {
                        DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(ResourceDefinition));
                        ResourceDefinition obj = (ResourceDefinition)ser.ReadObject(ms);
                    }
                }
                catch (Exception iex)
                {
                    dsMsg = iex.Message;
                    dxMsg = iex.ToString();
                }            
                MessageBox.Show(
                    string.Format(
                        "Malformed resdef json in package. While deserializing json {0} in package {1}. Exception details : " +
                        " JavaScriptSerializer: {2} {3} \n DataContractSerializer: {4} {5}", resourceDefinitionStorageInfo.JsonFileName, resourceDefinitionStorageInfo.FileToSavePath,
                         jsMsg, exMsg, dsMsg, dxMsg), DefinitionViewModel.ToolHeader);
                return;
            }       
            
            ViewDefinition viewDefinition = null;
            if (resourceDefinitionStorageInfo.IsResdefPkg)
            {
                if (resourceDefinitionStorageInfo.ViewDefFileName == null)
                {
                    string viewDefFileName = System.IO.Path.GetFileNameWithoutExtension(resourceDefinitionStorageInfo.JsonFileName) + ".viewdef";
                    //resourceDefinitionStorageInfo.ViewDefFileName = System.IO.Path.Combine(resourceDefinitionStorageInfo.WorkingDir, "1.viewdef");
                    resourceDefinitionStorageInfo.ViewDefFileName = System.IO.Path.Combine(resourceDefinitionStorageInfo.WorkingDir, viewDefFileName);
                    viewDefinition = new ViewDefinition();
                }
                else
                {
                    JavaScriptSerializer ser = new JavaScriptSerializer();
                    ser.RegisterConverters(new JavaScriptConverter[] { new ViewDefOptionValueJsonConverter() });                       
                    string viewDefDoc = System.IO.File.ReadAllText(resourceDefinitionStorageInfo.ViewDefFileName);
                    viewDefinition = ser.Deserialize<ViewDefinition>(viewDefDoc);
                }
            }

            VmRoleResourceDefinitionViewModel resDefViewModel = new VmRoleResourceDefinitionViewModel(deserializedObject, viewDefinition, resourceDefinitionStorageInfo, this.rootTreeViewItemViewModels, false);
            resDefViewModel.IsSelected = true;
            resDefViewModel.IsExpanded = true;
            this.rootTreeViewItemViewModels.Add(resDefViewModel);
        }


        /// <summary>
        /// Can throw exception
        /// InvalidCastException
        /// SerializationException exception
        /// </summary>
        /// <param name="resourceDefinitionStorageInfo"></param>      
        public void CreateAndAddNewResourceDefinitionToTheView(ResourceDefinitionStorageInfo resourceDefinitionStorageInfo)
        {        
            VmRoleResourceDefinitionViewModel resDefViewModel = VmRoleResourceDefinitionViewModel.CreateNewResourceDefinition(resourceDefinitionStorageInfo, this.rootTreeViewItemViewModels);
            resDefViewModel.IsSelected = true;
            resDefViewModel.IsExpanded = true;
            this.rootTreeViewItemViewModels.Add(resDefViewModel);
        }

        public ObservableCollection<CloudServiceModelValidationResult>  ValidationResults { get; private set; }

        public ICommand ValidateAllCommand
        {
            get;
            private set;
        }

        public bool CanValidateAll()
        {
            return true;
        }

        public void ValidateAll()
        {
            this.ValidationResults.Clear();
            foreach (TreeViewItemViewModel treeViewItemViewModel in this.rootTreeViewItemViewModels)
            {
                treeViewItemViewModel.IsExpanded = true;
                IProduceValidationResults produceValidationResults = treeViewItemViewModel as IProduceValidationResults;
                Debug.Assert(produceValidationResults != null);
                produceValidationResults.UpdateValidationResults();
                foreach (CloudServiceModelValidationResult result in produceValidationResults.ValidationResults)
                {
                    this.ValidationResults.Add(result);
                }
            }
            if (this.ValidationResults.Count == 0)
            {
                this.ValidationResults.Add
                    (
                    new CloudServiceModelValidationResult
                        {
                            ValidationCategory = ValidationCategory.Success,
                            Message = "There are 0 errors and 0 warnings",
                            TreeViewItemViewModel = null
                        });
            }

            //Add any other cross-field validations error            
        }       

        public void RemoveChild(TreeViewItemViewModel childItem)
        {
            

            VmRoleResourceExtensionViewModel vmRoleResourceExtensionViewModel = childItem as VmRoleResourceExtensionViewModel;
            if (vmRoleResourceExtensionViewModel != null)
            {
                if (System.Windows.Forms.MessageBox.Show("Save Resource Extension package?", DefinitionViewModel.ToolHeader, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
                {
                    vmRoleResourceExtensionViewModel.SaveToDisk();                  
                }
                this.rootTreeViewItemViewModels.Remove(vmRoleResourceExtensionViewModel);
                return;
            }
            VmRoleResourceDefinitionViewModel vmRoleResourceDefinitionViewModel = childItem as VmRoleResourceDefinitionViewModel;
            if (vmRoleResourceDefinitionViewModel != null)
            {
                if (System.Windows.Forms.MessageBox.Show("Save Resource Definition package?", DefinitionViewModel.ToolHeader, MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes)
                {
                    vmRoleResourceDefinitionViewModel.SaveToDisk();
                }
                this.rootTreeViewItemViewModels.Remove(vmRoleResourceDefinitionViewModel);
            }
        }
    }
}
